/**
 * 
 */
package de.cbf.cam.dsa.model.entities.items.transfers;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TransferData;

import de.cbf.cam.dsa.model.entities.WeaponStyle;
import de.cbf.cam.dsa.model.entities.weapon.OneWeapon;
import de.cbf.cam.dsa.model.entities.weapon.WeaponMelee;
import de.cbf.cam.dsa.model.entities.weapon.WeaponRanged;
import de.cbf.cam.dsa.model.entities.weapon.valueModifier.WeaponValueModifier;

/**
 * @author Nebelritter
 *
 */
public class WeaponTransfer extends ByteArrayTransfer implements ITransfer{
	private static final String TYPENAME = "weaponTransfer";

	private static final int TYPEID = registerType(TYPENAME);

	private static WeaponTransfer instance = new WeaponTransfer();
	
	public static WeaponTransfer getInstance() {
		return instance;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.swt.dnd.Transfer#getTypeIds()
	 */
	@Override
	protected int[] getTypeIds() {
		return new int[] { TYPEID };
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.swt.dnd.Transfer#getTypeNames()
	 */
	@Override
	protected String[] getTypeNames() {
		return new String[] { TYPENAME };		
	}	

	boolean checkItem(Object object) {
		return (object != null && object instanceof OneWeapon);
	}

	protected boolean validate(Object object) {
		return checkItem(object);
	}
	
	public void javaToNative(Object object, TransferData transferData) {
	      if (!checkItem(object) || !isSupportedType(transferData)) {
	        DND.error(DND.ERROR_INVALID_DATA);
	      }
	      OneWeapon weapon = (OneWeapon) object;
	      try {
	    	  // write data to a byte array and then ask super to convert to
	    	  // pMedium
	    	  ByteArrayOutputStream out = new ByteArrayOutputStream();
	    	  DataOutputStream writeOut = new DataOutputStream(out);
	    	 
	    	  writeWeapon(weapon, writeOut);
	    	  
	        
	    	  byte[] buffer = out.toByteArray();
	    	  writeOut.close();
	    	  
	    	  super.javaToNative(buffer, transferData);
	      } catch (IOException e) {
	      }
	    }

	  public Object nativeToJava(TransferData transferData) {
	  	if (isSupportedType(transferData)) {
	  		byte[] bufferAll = (byte[]) super.nativeToJava(transferData);
	  		if (bufferAll == null){
	  			return null;
	  		}
	  		
	  		try {
	  			ByteArrayInputStream in = new ByteArrayInputStream(bufferAll);
	  			DataInputStream readIn = new DataInputStream(in);
	  			OneWeapon weapon= null;
	  			while (readIn.available() > 20) {
	  				
	  				 weapon = readWeapon(readIn);
	  			}
		  		readIn.close();
		  		return weapon;
	        } catch (IOException ex) {	        	
	          return null;
	        }        
	    }
	    return null;
	  }
//		private static final int WEAPON_Base		= 1<<1;
	private static final int WEAPON_Melee		= 1<<2;
	private static final int WEAPON_Ranged		= 1<<3;
	
	static void writeWeapon(OneWeapon weapon,DataOutputStream writeOut) throws IOException{
		//write basedata
		TransferSubEntities.writeString(weapon.getGuid(),writeOut);		
		writeOut.writeInt(weapon.getPrice());
		writeOut.writeInt(weapon.getSpecialStates());
		TransferSubEntities.writeString(weapon.getWeaponType(),writeOut);
		writeOut.writeInt(weapon.getTpDiceNumber());
		writeOut.writeInt(weapon.getTpDiceSides());
		writeOut.writeInt(weapon.getTpBonus());
		
		//weaponMain styles
		int countOfStyles = weapon.getStyles().size();
		writeOut.writeInt(countOfStyles); 
		for(int i = 0;i<countOfStyles;i++ ){
			WeaponStyle weaponStyle = weapon.getStyles().get(i);
			TransferSubEntities.writeWeaponStyle(weaponStyle, writeOut);
		}
		
		//weaponMain value modifiers
		int countOfModifiers = weapon.getValueModifiers().size();
		writeOut.writeInt(countOfModifiers);
		for(int i = 0;i<countOfModifiers;i++ ){
			WeaponValueModifier modifier = weapon.getValueModifiers().get(i);
			TransferSubEntities.writeWeaponValueMod(modifier, writeOut);
		}
		
		if (weapon instanceof WeaponMelee) {
			WeaponMelee weaponMelee = (WeaponMelee) weapon;			
			writeOut.writeInt(WEAPON_Melee);			
			
			writeOut.writeInt(weaponMelee.getKKStep());
			writeOut.writeInt(weaponMelee.getKKTreshold());
			
			writeOut.writeInt(weaponMelee.getLength());

			writeOut.writeInt(weaponMelee.getBf());
			
			writeOut.writeInt(weaponMelee.getIniMod());
			
			writeOut.writeInt(weaponMelee.getWmAT());
			writeOut.writeInt(weaponMelee.getWmPA());
			
			writeOut.writeInt(weaponMelee.getDkBits());
						
			return;
		}
		if (weapon instanceof WeaponRanged) {
//				WeaponRanged weaponRanged = (WeaponRanged) weaponMain;			
			writeOut.writeInt(WEAPON_Ranged);			
						
			
			return;
		}		
	}
	static OneWeapon readWeapon(DataInputStream input) throws IOException{
		String guid 		= TransferSubEntities.readString(input);
		int price 			= input.readInt();
		int specialStates 	= input.readInt();
		String type 		= TransferSubEntities.readString(input);
		int tpDiceNumber 	= input.readInt();
		int tpDiceSides 	= input.readInt();
		int tpBonus			= input.readInt();
		
		List<WeaponStyle> styles = new ArrayList<WeaponStyle>();
		int countOfStyles = input.readInt();
		for(int i = 0;i< countOfStyles;i++){
			WeaponStyle style = TransferSubEntities.readWeaponStyle(input);
			styles.add(style);
			
		}
		List<WeaponValueModifier> modifiers = new ArrayList<WeaponValueModifier>();
		int countOfModifiers = input.readInt();
		for(int i = 0;i< countOfModifiers;i++){
			WeaponValueModifier modifier = TransferSubEntities.readWeaponValueMod(input);
			modifiers.add(modifier);
		}
		
		int weaponType = input.readInt();
		switch (weaponType) {
			case WEAPON_Melee:{
				WeaponMelee weapon = new WeaponMelee();
				int readInt = input.readInt();				
				weapon.setKKStep(readInt);
				
				readInt = input.readInt();
				weapon.setKKTreshold(readInt);
				
				readInt = input.readInt();
				weapon.setLength(readInt);

				readInt = input.readInt();
				weapon.setBf(readInt);
				
				readInt = input.readInt();
				weapon.setIniMod(readInt);
				
				readInt = input.readInt();
				weapon.setWmAT(readInt);
				readInt = input.readInt();
				weapon.setWmPA(readInt);
				
				readInt = input.readInt();
				weapon.setDkBits(readInt);
				
				setWeaponBaseData(weapon, guid,
						type,specialStates, price, 
						tpDiceNumber, tpDiceSides, tpBonus,
						styles, modifiers);
				return weapon;
			}
			case WEAPON_Ranged:{
				WeaponRanged weapon = new WeaponRanged();
				
				
				setWeaponBaseData(weapon, guid,
						type,specialStates, price, 
						tpDiceNumber, tpDiceSides, tpBonus,
						styles, modifiers);
				return weapon;
			}
		
		}
		return null;
	}
	
	private static void setWeaponBaseData(OneWeapon weapon,String guid,
			String type,int specialStates,int price,
			int tpDiceNumber,int tpDiceSides,int tpBonus,
			List<WeaponStyle> styles,List<WeaponValueModifier> modifiers){
		weapon.setGuid(guid);
		weapon.setPrice(price);
		weapon.setSpecialStates(specialStates);
		weapon.setWeaponType(type);
		weapon.setTpDiceNumber(tpDiceNumber);
		weapon.setTpDiceSides(tpDiceSides);
		weapon.setTpBonus(tpBonus);
		weapon.setStyles(styles);
		weapon.setValueModifiers(modifiers);
		
	}
	@Override
	public String toString() {
		return getClass().getSimpleName();
	}
}
